<template>
    <div>
        <!-- Class 与 Style 绑定 -->

        <!-- Class绑定 -->
        <!-- 对象语法 -->
        <!-- active 这个 class 存在与否将取决于数据 isActive -->
        <!-- 普通绑定的Class与动态绑定的Class可以并存 -->
        <!-- <div class="static" v-bind:class="{ active: isActive }">这是一个div标签</div> -->
        <!-- 我们也可以在这里绑定一个返回对象的计算属性。 -->
        <!-- <div class="static" v-bind:class="isCon">这是一个div标签</div> -->
        <!-- 数组语法 -->
        <!-- 字符串、表达式、三元表达式、对象 -->
        <!-- <div class="static" :class="['abc','def']">这是一个div标签</div> -->
        <!-- <div class="static" :class="['abc',isActive+'1']">这是一个div标签</div> -->
        <!-- <div v-bind:class="[isActive ? '123' : '', 'errorClass']">这是一个div标签</div> -->
        <!-- <div v-bind:class="[{active: isActive},'errorClass']">这是一个div标签</div> -->
        <!-- 用在组件上 -->
        <!-- <Test  :class="{ active: isActive }"/> -->

        <!-- 绑定内联样式 -->
        <!-- 对象语法 -->
        <!-- <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">这是一个div标签</div> -->
        <!-- 直接绑定到一个样式对象通常更好，这会让模板更清晰： -->
        <!-- <div v-bind:style="styleObject">这是一个div标签</div> -->
        <!-- 同样的，对象语法常常结合返回对象的计算属性使用。 -->

        <!-- 数组语法 -->
        <!-- <div v-bind:style="[styleObject,{color: activeColor}]">这是一个div标签</div> -->
        <!-- 自动添加前缀 -->
        <!-- 当 v-bind:style 使用需要添加浏览器引擎前缀的 CSS property 时，
        如 transform，Vue.js 会自动侦测并添加相应的前缀。 -->
        <!-- 多重值 -->
        <!-- 这样写只会渲染数组中最后一个被浏览器支持的值。在本例中，如果浏览器支持不带浏览器前缀的 flexbox，那么就只会渲染 display: flex。 -->
        <!-- <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">这是一个div标签</div> -->

        <!-- 计算属性vs方法 -->
        <!-- 计算属性是属性，方法是方法 -->
        <!-- 计算属性依赖值发生改变才会调用 -->
        <!-- 模板内的表达式非常便利，但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。 -->
        <!-- {{ message.split('').reverse().join('') }} -->
        <!-- 所以，对于任何复杂逻辑，你都应当使用计算属性。 -->
        <!-- 方法只要调用就会执行 -->
        <!-- {{msg}}**{{msgFn()}} -->
        <!-- {{msg}} -->
        <!-- <button @click="msgFn()">点击</button> -->

        <!-- 父子组件传参 -->
        <!-- 父组件向子组件传参 -->
        <!-- <Test :子组件props要接收属性="要传给子组件的参数"/> -->
        <!-- <Test :activeColor="activeColor"/> -->

        <!-- 子组件向父组件传参 -->
        <!-- 子组件通过this.$emit("父组件上的自定义事件","要传给父组件的参数")触发父组件上的自定义事件 -->
        <!-- <Test @autoClk="testFn"/> -->

        <!-- 插槽 -->
        <!-- 具名插槽(旧的设置方法) slot -->
        <!-- <p slot="header">我是p标签--header</p>
        <span>我是span标签--main</span>
        <div slot="footer">我是div标签--footer</div> 
        -->

        <!-- 具名插槽(新的设置方法) v-slot与<template></template>配合使用 -->
        <!-- <template v-slot:header>
            <p>我是p标签--header</p>
        </template>
        <template v-slot:default>
            <span style="display:block">我是span标签--main</span>
        </template>
        <template v-slot:footer>
            <div>我是div标签--footer</div>
        </template> 
        -->

        <!-- 作用域插槽(新的) 插槽内容可访问子组件中的数据,
        用v-slot定义插槽 prop 的名字slotProps(对象可以任意起名字) , 通过slotProps进行分发 -->
        <!-- <template v-slot:footer="slotProps">
            {{slotProps.user.lastName}}
        </template> -->

        <!--作用域插槽(旧的) slot-scope 只能是默认插槽  -->
        <!-- <template slot-scope="slotProps">
            {{slotProps.user.lastName}}
        </template> -->

        <!-- 独占默认插槽 -->
        <!-- <template v-slot="slotProps">
            {{slotProps.user.lastName}}
        </template> -->

        <!-- 解构插槽 Prop -->
        <!-- <template v-slot:jiegou="{user,age}">
            {{user.lastName}}--{{age}}
        </template> -->

        <!-- 动态插槽名 -->
        <!-- <template #[dynamicSlotName]>
            <div>我是div标签--footer</div>
        </template> -->


        <!-- 自定义指令 -->
        <!-- <textarea v-focus></textarea> -->
        <!-- <input type="text" v-if="isActive" v-focus="[1,2,3]" v-model="num">
        <button @click="isActive=!isActive">点击</button> -->

        <!-- 过滤器 -->
        <!-- {{ msg | filStr }}
        {{ obj.user.name | filStr }} -->

        <!-- 混入 -->
        <!-- {{clkFn()}} -->
        
        <!-- refs -->
        <!-- <span ref="span111">wer</span>
        <br>
        <input type="text" ref="ipt" value="1234"> -->
        <!-- <span ref="span">wer</span> -->


        <!-- 生命周期钩子 -->

        <!-- 数组变异方法 -->
        <!-- filter(), concat() 和 slice() 。这些不会改变原始数组，但总是返回一个新数组 -->
        <!-- push()pop()shift()unshift()splice()sort()reverse()会改变被这些方法调用的原始数组 -->


        <!-- watch侦听器 -->
        <!-- <input type="text" v-model="num">  -->
        <!-- <input type="text" v-model="obj.gender"> -->
        <!-- <input type="text" v-model="obj.user.age"> -->

        <!-- <input type="text" v-model="firstName">
        <div>{{ nameFn }}</div> -->
    </div>
</template>

<script>
import Test from "@/components/Test";
import myMixin from "@/js/test";
export default {
  data() {
    return {
      isActive: true,
      activeColor: "red",
      fontSize: "20",
      styleObject: {
        color: "green",
        fontSize: "30px"
      },
      message: "wefkjneg",
      dynamicSlotName: "footer",
      num: 0,
      obj: {
        user: {
          name: "hekaipeng"
        },
        age: 18
      }
    };
  },
  mixins : [myMixin],
  // beforeCreate(){//在组件属性还未创建完成如：data,methods等   //还不能使用
  //   console.log('app-beforeCreate')
  // },
  // created(){//组件创建成功，但模板还没编译，dom不存在
  //   // console.log(this.$refs.span)
  //   console.log('app-created')
  // },
  // beforeMount(){//开始编译模板html  //挂载之前编译
  //   console.log('app-beforeMount')
  // },
  // mounted(){//模板编译成功,并把实例挂载到dom元素上
  // console.log(this.$el)
  //   console.log('app-mounted')
  // },
  // beforeUpdate(){//在data被修改时
  //   console.log('app-beforeUpdate')
  // },
  // updated(){//修改完成
  //   console.log('app-updated')
  // }
  directive: {
    focus: {
      //当绑定成功
      // expression：字符串形式的指令表达式,v-focus等号里边是什么就是什么  //可以传字符串，数组，对象等
      // value：指令的绑定值  //只在update和componentUpdated里边使用
      // oldValue：旧的值   //只在update和componentUpdated里边使用
      // rawName：等号之前是指令的全称
      // arg(参数):冒号之后，等号之前
      // modifiers：一个包含修饰符的对象
      // 先传参，再传修饰符
      //     bind(el,binding,vnode,oldVnode){//只调用一次，指令第一次绑定到元素时调用
      //       // console.log('bind');
      //       console.log(oldVnode)
      //     },
      //     inserted(el,binding,vnode,oldVnode){//被绑定元素插入父节点时调用
      //       // console.log('inserted');
      //       console.log(binding)
      //       console.log(oldVnode)
      //     },
      //     // 组件dom更新时调用
      //     update(el,binding,vnode,oldVnode){//虚拟dom修改完成时调用
      //       // console.log('update')
      //       console.log(oldVnode)
      //     },
      //     componentUpdated(el,binding,vnode,oldVnode){//真实dom更新后调用
      //       // console.log('componentUpdated')
      //       console.log(oldVnode)
      //     },
      //     // 解绑调用
      //     unbind(el,binding,vnode,oldVnode){//只调用一次，指令与元素解绑时调用
      //       // console.log('unbind')
      //       console.log(oldVnode)
      //     }
    }
  },
  methods: {
    testFn(a) {
      // 子组件向父组件传参 a -->{a:1}
      console.log(a);
      this.isActive = false;
      this.dynamicSlotName = "header";
    },
    msgFn() {
      console.log("方法被调用");
      this.message = "hello";
      return this.message
        .split("")
        .reverse()
        .join("");
    }
  },
  computed: {
    isCon() {
      return !this.isActive ? "abc" : "def";
    },
    msg() {
      console.log("计算属性被调用");
      return this.message
        .split("")
        .reverse()
        .join("");
    }
  },
  watch: {
    // num : function (newVal,preVal) {
    //   console.log(newVal)
    //   console.log(preVal)
    // }
    // num (newVal,preVal) {
    //     console.log(newVal)
    //     console.log(preVal)
    // }
    // num : 'WatFn'
    // obj : 'WatFn'//监听对象//监听不到obj.gender
    // obj: {
    //   handler(newVal, preVal) {
    //     console.log(newVal);
    //     console.log(preVal);
    //   },
    //   deep : true,//深度监听
    //   immediate : true//页面初始化的时候调用一次//旧值为undefined
    // }
    // "obj.user.age": {
    //   handler(newVal, preVal) {
    //     console.log(newVal);
    //     console.log(preVal);
    //   },
    //   immediate: true
    // }
    // firstName: function(newVal, preVal) { //代码是命令式且重复的。将它与计算属性的版本进行比较
    //   this.fullName = newVal + " " + this.lastName;
    // },
    // lastName: function(newVal, preVal) {
    //   this.fullName = this.lastName + " " +  newVal;
    // }
  },
  filters: {
    //过滤器
    // filStr : function (v) {//只有这个组件能使
    //   console.log(v)
    //   // return aaa //不要改变值//只改变文本
    //   return v.charAt(0).toUpperCase() + v.slice(1)
    // }
    filStr(v) {
      //也能简写
      console.log(v);
      // return aaa //不要改变值//只改变文本
      return v.charAt(0).toUpperCase() + v.slice(1);
    }
  },
  components: {
    Test
  }
};
</script>

<style scoped>
</style>